﻿/*
 * Copyright the original author or authors.
 * 
 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.mozilla.org/MPL/MPL-1.1.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.bourre.commands.AbstractSyncCommand;
import com.bourre.commands.ISyncCommand;
import com.bourre.events.IEvent;
import com.bourre.log.PixlibStringifier;
import com.bourre.transitions.IFrameListener;
import com.kairos.engine.RTBeacon;
import com.kairos.engine.RTEvent;
import com.kairos.engine.RTAnimation;
import com.kairos.log.KairosDebug;
import com.kairos.engine.RTObject;
import com.bourre.commands.ISyncCommandListener;
import com.prizee.log.AIRLoggerAS2;

/**
 * A {@code IntervalRT} object work as a call of the {@code setInterval} method
 * but can be paused, restart, and synchronized with the whole application
 * run dint {@code RTBeacon}.
 * 
 * <p>Because of scope issues you have to specify the function scope when
 * you create a new {@code IntervalRT} object.</p>  
 * 
 * <p>{@code IntervalRT} implements the {@code ISyncCommand} interface, so you could
 * use it with a {@code StepCommandManager}, or in your {@code FrontController}.</p>
 * 
 * @author	Cédric Néhémie
 * @example	import com.kairos.commands.IntervalRT;
 * 
 * var myInterval : IntervalRT = new IntervalRT ( this, myFunction, 1000, "someParam" );
 * myInterval.start (); 
 */
class com.kairos.commands.IntervalRT extends RTObject implements RTAnimation, ISyncCommand
{
	private var _oT;
	private var _f : Function;
	private var _d :  Number;
	private var _a : Array;
	private var _n : Number;
	private var _nCount : Number;
	private var _nIteration : Number;
	
	/**
	 * Create a new {@code IntervalRT} object.
	 * 
	 * <p>You have to call the {@link #execute} or {@link #start} method to start
	 * the Interval run.</p>
	 * 
	 * <p>You can specify additionnal arguments to pass to the function.</p>
	 *	
	 * @param	o	The object in witch scope the function is run.
	 * @param	f	The function to call.
	 * @param	d	The delay of the Interval.
	 * @param	c	{@code Number} of iterations of the interval
	 * @example	var myInterval : IntervalRT = new IntervalRT ( this, myFunction, 1000 );
	 * @example	var myInterval : IntervalRT = new IntervalRT ( this, myFunction, 1000, 5 );
	 * @example	var myInterval : IntervalRT = new IntervalRT ( this, myFunction, 1000, 5, "someParam" );
	 */	
	public function IntervalRT ( o, f : Function, d : Number, c : Number )
	{
		_oT = o;
		_f = f;
		_d = d;
		reset();
		_nCount = !isNaN(c) && c >= 0 ? c : 0;
		_a = arguments.splice ( 4 );
	}
	
	/**
	 * Method called by the {@code RTBeacon} object.
	 * 
	 * <p>For each step of the run the current step is added
	 * to the time clock. The current step is get from the
	 * {@code RTBeacon}.</p>
	 * 
	 * <p>The function get a {@code BasicEvent} when called, 
	 * but the function doesn't show it because {@code IFrameListener}
	 * implementation.</p>
	 */
	public function onEnterFrame () : Void
	{		
		_n += getLocalStep( arguments[ 0 ] );
		
		if( _n >= _d )
		{
			_f.apply ( _oT, _a );
			_n -= _d;
			if( _nCount && ++_nIteration >= _nCount )
			{
				stop();
				fireCommandEndEvent();
				reset();
			}
		}
	}
	
	/**
	 * Place the time clock to 0, if the {@code IntervalRT} is running
	 * it proceed the run.
	 */
	public function reset () : Void
	{
		_n = 0;
		_nIteration = 0;
	}
	
	/**
	 * Defines the number of iterations the interval has to realize
	 * during its run.
	 * 
	 * <p>When the interval is running, if the specified value is lower
	 * than the current iteration, the interval will stop at the next
	 * interval.</p>
	 * 
	 * <p>If set to 0, the count is deactivate.</p>
	 * 
	 * @param 	c	{@code Number} of iteration to perform.
	 */
	public function setCount ( c : Number ) : Void
	{
		_nCount = c;
	}
	
	/**
	 * Returns the current iteration of this object.
	 * 
	 * @return the current iteration of this object.
	 */
	public function getIteration () : Number
	{
		return _nIteration;
	}
	
	/**
	 * Returns the current count limit for this object.
	 * 
	 * @return the current count limit for this object.
	 */
	public function getCount() : Number
	{
		return _nCount;
	}
	
	/**
	 * Defines the delay between each call.
	 * 
	 * <p>When running, if the specified delay is
	 * lower than the current internal timer, the
	 * command will be called at the next step.</p> 
	 * 
	 * @param	d	Number of milliseconds between calls
	 */
	public function setDelay ( d : Number ) : Void
	{
		_d = d;
	}
	
	/**
	 * Returns the current delay between calls for this object.
	 * 
	 * @return the current delay between calls for this object
	 */
	public function getDelay () : Number
	{
		return _d;
	}
	
	/**
	 * Defines arguments to pass to the function.
	 */
	public function setArguments() : Void
	{
		_a = arguments;
	}
	
	/**
	 * Returns the current arguments to pass to the function.
	 * 
	 * @return {@code Array} of arguments to pass to the function.
	 */
	public function getArguments() : Array
	{
		return _a;
	}
	
	/**
	 * <p>A warning is send to the debugger if you are trying
	 * to use an interval witch have no limit for execution.</p>
	 * 
	 * @inheritDocs
	 */
	public function addListener( listener : ISyncCommandListener ) : Void
	{
		if( _nCount == 0 ) 
			KairosDebug.WARN( listener + " have registered to an object witch will not fire the onCommandEnd event : " + this ); 
		
		super.addListener( listener );			
	}
		
	/**
	 * Return the string representation of the object 
	 */	
	public function toString() : String
	{
		return PixlibStringifier.stringify( this );
	}
}